#include "../source/vlib.h"
#include <stdio.h>


static void test_create(void)
{
	list_t list = list(int);
	_list(list);
}

static void test_push_pop(void)
{
	list_t list = list(int);
	
	for (int i = 0; i < 3; i++)
	{
		list_push_front(list, &i);
		list_push_back(list, &i);
	}
	
	for (int i = 0; i < 6; i++)
	{
		list_pop_front(list);
	}
	
	_list(list);
} 

static void test_at(void)
{
	list_t list = list(int);
	
	for (int i = 0; i < 6; i++)
	{
		list_push_back(list, &i);
	}
	
	for (int i = 0; i < 6; i++)
	{
		printf("list[%d] = %d\r\n", i, list_at(list, int, i));
	}
	
	_list(list);
}

static void test_error(void)
{
	list_t list = list(int);
	int i = 0;

	for (i = 0; i < 8; i++)
	{
		list_push_back(list, &i);
	}
	
	list_at(list, int, 100) = 100; // An invalid index was manipulated
	
	if (&list_at(list, int, 100) == list_error(list))
	{
		printf("error!\r\n");
	}

	_list(list);
}

static void test_get_alter(void)
{
	list_t list = list(int);
	int i = 0;
	
	for (i = 0; i < 8; i++)
	{
		list_push_back(list, &i);
	}
	
	if (list_get(list, 5, &i)) printf("get = %d\r\n", i);
	
	if (list_alter(list, 5, la(int, 100))) printf("alter = %d\r\n", list_at(list, int, 5));
	
	_list(list);
}

static void test_insert(void)
{
	list_t list = list(int);
	int i = 0;
	
	for (i = 0; i < 8; i++)
	{
		list_push_back(list, &i);
	}
	
	list_insert(list, 5, la(int, 100));
	
	for (i = 0; i < list_size(list); i++)
	{
		printf("at = %d\r\n", list_at(list, int, i));
	}
	
	_list(list);
}

static void test_erase(void)
{
	list_t list = list(int);
	int i = 0;
	
	for (i = 0; i < 8; i++)
	{
		list_push_back(list, &i);
	}
	
	list_erase(list, 2, 5);
	
	for (i = 0; i < list_size(list); i++)
	{
		printf("at = %d\r\n", list_at(list, int, i));
	}
	
	_list(list);
}

static void test_copy(void)
{
	list_t list = list(int);
	list_t copy = NULL;
	int i = 0;
	
	for (i = 0; i < 8; i++)
	{
		list_push_back(list, &i);
	}
	
	copy = list_copy(list, 2, 5);
	
	for (i = 0; i < list_size(copy); i++)
	{
		printf("at = %d\r\n", list_at(copy, int, i));
	}
	
	_list(list);
	_list(copy);
}

static void test_switch(void)
{
	list_t list = list(int);
	int i = 0;
	
	for (i = 0; i < 6; i++)
	{
		list_push_back(list, &i);
	}
	
	list_switch(list, 2, 4);

	for (i = 0; i < list_size(list); i++)
	{
		printf("at = %d\r\n", list_at(list, int, i));
	}
	
	_list(list);
}

static void test_reverse(void)
{
	list_t list = list(int);
	int i = 0;
	
	for (i = 0; i < 6; i++)
	{
		list_push_back(list, &i);
	}
	
	list_reverse(list, 1, 5);

	for (i = 0; i < list_size(list); i++)
	{
		printf("at = %d\r\n", list_at(list, int, i));
	}
	
	_list(list);
}

static void test_splice(void)
{
	list_t list = list(int);
	int i = 0;
	
	for (i = 0; i < 6; i++)
	{
		list_push_back(list, &i);
	}
	
	list_splice(list, 3, list, 2, 4);
	
	for (i = 0; i < list_size(list); i++)
	{
		printf("at = %d\r\n", list_at(list, int, i));
	}
	
	_list(list);
}

static int sort_rule_int(void* front, void* back)
{
    if (*(int *)front < *(int *)back) return 1;
    else if (*(int *)front > *(int *)back) return -1;
    return 0;
}

static void test_sort(void)
{
	list_t list = list(int);
    int array[] = {5, 4, 3, 99, 100, -5};
    int i = 0;

    for (i = 0; i < sizeof(array)/sizeof(array[0]); i++)
    {
        list_push_back(list, &array[i]);
    }
	
    list_sort(list, 0, list_size(list) - 1, sort_rule_int);
	
    for (i = 0; i < list_size(list); i++)
    {
        printf("at = %d\r\n", list_at(list, int, i));
    }

    _list(list);
}

static void test_insert_sort(void)
{
	list_t list = list(int);
    int i = 0;
	
	list_insert_sort(list, la(int, 100), sort_rule_int);
	list_insert_sort(list, la(int, -1), sort_rule_int);
	list_insert_sort(list, la(int, 10), sort_rule_int);
	list_insert_sort(list, la(int, -99), sort_rule_int);
	list_insert_sort(list, la(int, 120), sort_rule_int);
	list_insert_sort(list, la(int, 6), sort_rule_int);
	
    for (i = 0; i < list_size(list); i++)
    {
        printf("at = %d\r\n", list_at(list, int, i));
    }

    _list(list);
}

static void list_show(int index, void* data)
{
    printf("list[%d] = %d\r\n", index, *(int *)data);
}

static void test_traverse(void)
{
    list_t list = list(int);
    int i = 0;
    
    for (i = 0; i < 8; i++)
    {
        list_push_back(list, &i);
    }
	
    list_traverse(list, LIST_DIR_H2T, list_show);

    _list(list);
}

static int list_condition(void* ref, void* cmp, int dsize)
{
    if (*(int *)cmp < *(int *)ref)
    {
        return 1;
    }
    return 0;
}

static void test_find(void)
{
    list_t list = list(int);
    int *ptr;
	int index = 0;
	
	list_push_back(list, la(int, 100));
	list_push_back(list, la(int, -1));
	list_push_back(list, la(int, 10));
	list_push_back(list, la(int, -99));
	list_push_back(list, la(int, 120));
	list_push_back(list, la(int, 6));
	
	ptr = list_find(list, la(int, 120), LIST_DIR_H2T, 0, &index);
	if (ptr != list_error(list))
	{
		printf("find: list[%d] = %d\r\n", index, *ptr);
	}
	
	ptr = list_find_if(list, la(int, 0), LIST_DIR_H2T, 0, &index, list_condition);
	if (ptr != list_error(list))
	{
		printf("find_if: list[%d] = %d\r\n", index, *ptr);
	}
	
	ptr = list_find_ex(list, la(int, 0), 2, 4, LIST_DIR_H2T, 0, &index, list_condition);
	if (ptr != list_error(list))
	{
		printf("find_ex: list[%d] = %d\r\n", index, *ptr);
	}

    _list(list);
}

static void test_remove(void)
{
    list_t list = list(int);
	int array[] = {5, 4, 4, 99, 100, 4};
    int i = 0;

    for (i = 0; i < sizeof(array)/sizeof(array[0]); i++)
    {
        list_push_back(list, &array[i]);
    }
	
	i = list_remove(list, la(int, 4));
	printf("---------------- remove %d ----------------\r\n", i);
	list_traverse(list, LIST_DIR_H2T, list_show);

	i = list_remove_if(list, la(int, 6), list_condition);
	printf("---------------- remove_if %d ----------------\r\n", i);
	list_traverse(list, LIST_DIR_H2T, list_show);
	
	i = list_remove_ex(list, la(int, 100), 0, list_size(list) - 1, LIST_DIR_T2H, 6, list_condition);
	printf("---------------- remove_ex %d ----------------\r\n", i);
	list_traverse(list, LIST_DIR_H2T, list_show);

    _list(list);
}

void test_list(void)
{
	// test_create();
	// test_push_pop();
	// test_at();
	// test_error();
	// test_get_alter();
	// test_insert();
	// test_erase();
	// test_copy();
	// test_switch();
	// test_reverse();
	// test_splice();
	// test_sort();
	// test_insert_sort();
	// test_traverse();
	// test_find();
	test_remove();
} 
